package by.parfen.game.websocket;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import by.parfen.game.datamodel.GameMessage;
import by.parfen.game.service.GameMessageService;
import by.parfen.game.service.impl.GameMessageServiceImpl;

@ServerEndpoint(value = "/websocket-game/{ws-name}", configurator = WebSocketConfigurator.class)
public class GameWebsocket {

	private static final Logger LOGGER = Logger.getLogger(GameWebsocket.class.getName());

	private Session wsSession;
	private HttpSession httpSession;

	private static Set<Session> wsSessions = new HashSet<Session>();
	private static Map<String, Session> wsSessionsMap = new HashMap<String, Session>();
	private static Map<String, HttpSession> httpSessionsMap = new HashMap<String, HttpSession>();

	private static GameMessageService gameMessageService = new GameMessageServiceImpl();

	@OnOpen
	public void onOpen(Session session, EndpointConfig config, @PathParam("ws-name") String wsName) {

		// sore wsName as session user property
		session.getUserProperties().put("ws-name", wsName);
		this.wsSession = session;
		this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

		wsSessions.add(session);
		wsSessionsMap.put(this.httpSession.getId(), this.wsSession);
		httpSessionsMap.put(this.httpSession.getId(), this.httpSession);

		System.out.println("NEW Websocket Session: " + this.wsSession.getId() + ", ws-name:" + wsName);
		System.out.println("NEW HTTP Session: " + this.httpSession.getId());
		System.out.println("wsSessionMap: " + wsSessionsMap);
		System.out.println("httpSessionMap: " + httpSessionsMap);

		this.httpSession.setAttribute("countOfSession", httpSessionsMap.size());
		System.out.println("httpSessionsMap.size: " + httpSessionsMap.size());

		this.httpSession.setAttribute("httpSessionsMap", httpSessionsMap);
		LOGGER.info("added Map as session attribute");

	}

	@OnClose
	public void onClose(Session session) {
		wsSessions.remove(session);
		wsSessionsMap.remove(this.httpSession.getId());
		httpSessionsMap.remove(this.httpSession.getId());
		System.out
				.println("Websocket session " + session.getId() + " has ended, HTTP Session: " + this.httpSession.getId());
		this.httpSession.setAttribute("countOfSession", httpSessionsMap.size());
		this.httpSession.setAttribute("httpSessionsMap", httpSessionsMap);
	}

	@OnMessage
	public void onMessage(String message, Session session, @PathParam("ws-name") String wsName) throws IOException {
		LOGGER.info("wsName: " + wsName);
		GameMessage gameMessage = gameMessageService.decode(message);
		if (gameMessage != null) {
			LOGGER.info("Server received the games message " + gameMessage);
		}

		wsSession.getBasicRemote().sendText("Resend message:" + message);
		LOGGER.info("WS-Game, last user: " + this.httpSession.getAttribute("lastUser"));

		synchronized (wsSessions) {
			// Iterate over the connected sessions
			// and broadcast the received message
			for (Session wsSession : wsSessions) {
				String sessionWsName = wsSession.getUserProperties().get("ws-name").toString();
				System.out.println("user property: " + sessionWsName);
				if (sessionWsName != null && wsName.equals(sessionWsName) && !wsSession.equals(session) && wsSession.isOpen()) {
					try {
						wsSession.getBasicRemote()
								.sendText(String.format("Resend message {%s} to %s: %s", wsName, wsSession.getId(), message));
					} catch (IOException ex) {
						ex.printStackTrace();
					}
				}
			}
		}
	}

	@OnError
	public void onError(Session session, Throwable t) {
		LOGGER.info("Error for session: " + session.getId());
		t.printStackTrace();
	}

}